﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using DBCore.Attr;


namespace DBCore
{
    public class IOC
    {
        public static Dictionary<string, TypeAttr> Types = new Dictionary<string, TypeAttr>();  //類型集合
        public static Dictionary<Type, PropertyInfo[]> TypePropertyInfos = new Dictionary<Type, PropertyInfo[]>();
        public static Dictionary<Type, Dictionary<PropertyInfo, EntityPropertyAttribute>> EntityPropertyAttributes = new Dictionary<Type, Dictionary<PropertyInfo, EntityPropertyAttribute>>();
        public static Dictionary<Type, EntityAttribute> EntityAttributes = new Dictionary<Type, EntityAttribute>();
        public static List<Assembly> Assemblies = new List<Assembly>();

        private static void PushAssembly(Assembly ass)
        {
            try
            {
                if (!ass.GlobalAssemblyCache)
                {
                    Assemblies.Push(ass);
                    var refearray = ass.GetReferencedAssemblies();
                    refearray.ToList().ForEach(refeass => PushAssembly(Assembly.Load(refeass)));
                }
            }
            catch
            { 
            
            }
        }

        static IOC()
        {
            var array = AppDomain.CurrentDomain.GetAssemblies();
            array.ToList().ForEach(PushAssembly);
            foreach (var ass in Assemblies)
            {
                try
                {
                    if (ass.GlobalAssemblyCache) continue;
                    var types = ass.GetTypes();
                    foreach (var t in types)
                    {
                        lock (Types)
                        {
                            if (Types.ContainsKey(t.FullName)) continue;
                            Types.Add(t.FullName, t);
                            if (!t.IsSubclassOf(typeof(Entity))) continue;
                            var propertyattrs = new Dictionary<PropertyInfo, EntityPropertyAttribute>();
                            var propertys = new List<PropertyInfo>(IOC.GetProperties(t));
                            foreach (var p in propertys)
                            {
                                var attributes = p.GetCustomAttributes(typeof(EntityPropertyAttribute), false);
                                if (attributes.Length <= 0) continue;
                                var attr = (EntityPropertyAttribute)attributes[0];
                                propertyattrs.Add(p, attr);
                            }
                            EntityPropertyAttributes.Add(t, propertyattrs);
                            var typeattributes = t.GetCustomAttributes(typeof(EntityAttribute), true);
                            if (typeattributes.Length > 0)
                            {
                                EntityAttributes.Add(t, (EntityAttribute)typeattributes[0]);
                            }
                        }
                    }
                }
                catch
                { 
                
                }
            }

        }
        public static PropertyInfo[] GetProperties(Type t)
        {
            if (TypePropertyInfos.ContainsKey(t))
            {
                return TypePropertyInfos[t];
            }
            else
            {
                var pros = t.GetProperties();
                TypePropertyInfos[t] = pros;
                return pros;
            }
        }

        public static T CreateInstance<T>(string typename) where T : class
        {
            var t = Types[typename].ThisType;
            var o = Activator.CreateInstance(t);
            T r = o as T;
            return r;
        }

        /// <summary>
        /// 获取所以派生类型
        /// </summary>
        /// <param name="basetype"></param>
        /// <returns></returns>
        public static List<string> GetSubTypes(string basetype)
        {
            return Types[basetype].ChildTypes;
        }

        /// <summary>
        /// 获取所以派生类型
        /// </summary>
        /// <param name="basetype"></param>
        /// <param name="nestedtype"></param>
        /// <returns></returns>
        public static List<string> GetSubTypes(string basetype, string nestedtype)
        {
            var types = Types[basetype].ChildTypes;
            return (from t in types select Types[t] into type where type != null && type.ThisType.BaseType != null && type.ThisType.BaseType.FullName.IndexOf("[[" + nestedtype + ",", System.StringComparison.Ordinal) != -1 select type.ThisType.FullName).ToList();
        }
    }
}
